package com.flyxiaozhu.erp.core.utils;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;


import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Nekoing on 2016/6/27.
 */
@Slf4j
public class HttpUtils {
    final static public String CHARSET = "UTF-8";

    final static private int httpTimeOut = 30000;

    static public Object get(String url) throws IOException {
        return get(url, null, null, true);
    }

    static public <T> Object get(String url, Map<String, T> params) throws IOException {
        return get(url, params, null, true);
    }

    static public <T> Object get(String url, Map<String, T> params, Map<String, String> headers, boolean json) throws IOException {
        if (params != null && params.size() > 0) {
            url = urlCatParams(url, HttpUtils.buildQuery(params, CHARSET));
        }

        log.debug("http request: " + url);

        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(url);

        return doQuery(httpClient, httpGet, headers, json);
    }

    static public <T> Object post(String url, String body, boolean json) throws IOException {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        HttpEntity entity = new StringEntity(body);
        httpPost.setEntity(entity);
        return doQuery(httpClient, httpPost, json);
    }

    static public <T> Object post(String url, Map<String, T> params) throws IOException {
        return post(url, params, true);
    }

    static public <T> Object post(String url, Map<String, T> params, boolean json) throws IOException {
        log.debug("http request: " + url + "; " + HttpUtils.buildQuery(params, CHARSET));

        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        if (params != null && params.size() > 0) {
            List<NameValuePair> paramsList = new ArrayList<NameValuePair>();
            for (String key : params.keySet()) {
                paramsList.add(new BasicNameValuePair(key, String.valueOf(params.get(key))));
            }

            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramsList, CHARSET);
            httpPost.setEntity(entity);
        }

        return doQuery(httpClient, httpPost, json);
    }

    static public Object postXml(String url, String xml, boolean json) throws Exception {
        RequestConfig defaultRequestConfig = RequestConfig.custom()
                .setSocketTimeout(httpTimeOut)
                .setConnectTimeout(httpTimeOut)
                .setConnectionRequestTimeout(httpTimeOut)
                .build();

        SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
                return true;
            }
        }).build();

        CloseableHttpResponse response = null;
        String result = null;

        CloseableHttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).
                setSSLHostnameVerifier(new NoopHostnameVerifier()).setDefaultRequestConfig(defaultRequestConfig).build();

        HttpPost httpPost = new HttpPost(url);
        StringEntity entity = new StringEntity(xml);
        httpPost.setEntity(entity);
        httpPost.setHeader("Content-Type", "text/xml;charset=ISO-8859-1");

        response = httpClient.execute(httpPost);
        if (response.getStatusLine().getStatusCode() != 200) {
            throw new IOException("HttpUtils status error, code: " + response.getStatusLine().getStatusCode());
        }
        HttpEntity ResponseEntity = response.getEntity();

        result = EntityUtils.toString(ResponseEntity, CHARSET);
        httpClient.close();
        return result;
    }

    static public String urlCatParams(String url, String paramsStr) {
        if (url.indexOf('?') > 0) {
            return url + "&" + paramsStr;
        } else {
            return url + "?" + paramsStr;
        }
    }

    static protected Object doQuery(CloseableHttpClient httpClient, HttpUriRequest request, boolean json) throws IOException {
        return doQuery(httpClient, request, null, json);
    }

    static protected Object doQuery(CloseableHttpClient httpClient, HttpUriRequest request, Map<String, String> headers, boolean json) throws IOException {
        CloseableHttpResponse response = null;
        String result = null;

        try {
            if (headers != null) {
                for (Map.Entry<String, String> header : headers.entrySet()) {
                    request.setHeader(header.getKey(), header.getValue());
                }
            }
//            request.setHeader("Content-Type", "text/html;charset=" + CHARSET);
            response = httpClient.execute(request);
            if (response.getStatusLine().getStatusCode() != 200) {
                throw new IOException("HttpUtils status error, code: " + response.getStatusLine().getStatusCode());
            }

            HttpEntity entity = response.getEntity();
            result = EntityUtils.toString(entity, CHARSET);
            log.debug("HTTP Response:" + result);

            if (json) {
                return new Gson().fromJson(result, new TypeToken<HashMap<String, Object>>() {
                }.getType());
            } else {
                return result;
            }
        } catch (IOException e) {
            throw e;
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException ignore) {
            }
        }
    }

    static public <T> String buildQuery(Map<String, T> params) {
        return buildQuery(params, "UTF-8", true);
    }

    static public <T> String buildQuery(Map<String, T> params, boolean encode) {
        return buildQuery(params, "UTF-8", encode);
    }

    static public <T> String buildQuery(Map<String, T> params, String charset) {
        return buildQuery(params, charset, true);
    }

    static public <T> String buildQuery(Map<String, T> params, String charset, boolean encode) {
        String result = "";
        if (params == null || params.size() == 0) {
            return result;
        }

        for (String key : params.keySet()) {
            try {
                if (encode) {
                    result += URLEncoder.encode(key, charset) + "=" + URLEncoder.encode(String.valueOf(params.get(key)), charset) + "&";
                } else {
                    result += key + "=" + String.valueOf(params.get(key)) + "&";
                }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }

        result = result.substring(0, result.length() - 1);

        return result;
    }
}
